package ua.edu.nuos.jeetraining2012.cms.util.svn;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ua.edu.nuos.jeetraining2012.cms.util.svn.exception.SvnException;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: artur
 * Date: 26.06.13
 * Time: 15:59
 * To change this template use File | Settings | File Templates.
 */
public class SvnRepository {
    /**
     * Define logger.
     */
    final static private Logger logger = LoggerFactory.getLogger(SvnRepository.class);

    Map<String, String> admin = RepositoryProperties.getAdmin();

    /**
     * Create repository
     *
     * @param   repositoryName
     *          string - name of creating repository
     * @throws  IOException
     *          if repository already Exist
     *          if can't create repository
     */
    public boolean createRepository(String repositoryName) throws IOException, SvnException {
        logger.debug("createRepository() - invocation");

        String svnRootPath = RepositoryProperties.getPath();

        if(!isExistRepository(repositoryName)){

            String[] commands = new String[]{"svnadmin", "create", svnRootPath+"/"+repositoryName};
            Process process = Runtime.getRuntime().exec(commands);
            try{
                isProcessErrors(process);
            }catch (SvnException e){
                logger.warn("Can't create repository with "+repositoryName, e.getMessage()+" Name. {}", e.getMessage());
                throw new SvnException("Can't create repository with "+repositoryName+" Name \n"+ e.getMessage());
            }
        } else {
            logger.warn("Can't create repository with "+repositoryName+" Name. Already Exist.");
            throw new SvnException("Can't create repository with "+repositoryName+" Name. Already Exist.");
        }
        return true;
    }

    /**
     * Method check that is exist repository at SVN root Directory
     *
     * @param   repositoryName
     *          string - name of finding repository
     * @return  true if finding repository is Exist
     *          false - otherwise
     *
     */
    public boolean isExistRepository(String repositoryName) throws IOException{
        logger.debug("isExistUserRepository() - invocation");

        String svnRootPath = RepositoryProperties.getPath();
        File svnRoot = new File(svnRootPath);
        if (!svnRoot.exists()) {
            logger.debug("Svn root directory not found at "+svnRoot);
            createDirectory(svnRootPath);
        }

        File svnRepository = new File(svnRootPath+"/"+repositoryName);
        if (svnRepository.exists()) {
            return true;
        } else{
            logger.debug("Svn repository not found at {}", svnRepository);
            return false;
        }
    }


    public String importUserFolder(String repository, String folder) throws SvnException {
        String link;
        if (!isExistFolderInRepository(repository, folder)) {
            link = doImport(repository, folder);
        } else{
            System.out.println("Folder " + folder + " Already Exist");
            throw new SvnException("Folder " + folder + " Already Exist");
        }
        return link;
    }

    /**
     * Method do import user root folder into chosen repository
     * @param   repository
     *          string chosen repository
     * @param   folder
     *          string user root folder
     * @throws  SvnException
     *          if an I/O error occurs
     */
    public String doImport(String repository, String folder) throws SvnException {
        String tempDir = "/tmp/" + folder;
        String link;
        try {
            createDirectory(tempDir);

            String[] commands = new String[]{"svn", "import", tempDir,
                    "--username", admin.get("name"), "--password", admin.get("passwd"),
                    "--no-auth-cache", "--non-interactive",
                    "svn://localhost/" + repository + "/" + folder, "-m", "mess"};

            Process process = Runtime.getRuntime().exec(commands);
            isProcessErrors(process);
            link = "snv://" + RepositoryProperties.getServerUrl() + "/" + repository + "/" + folder;
        } catch (IOException e) {
            System.out.println("IOException importUserFolder - " + e.getMessage());
            throw new SvnException("IOException importUserFolder - " + e.getMessage());
        } finally {
            try {
                removeDirectory(tempDir);
            } catch (IOException e) {
                System.out.println("Can't delete temp directory "+e.getMessage());
                throw new SvnException("Can't delete temp directory "+e.getMessage());
            }
        }
        return link;
    }

    /**
     * Check that is Exist user folder in chosen repository
     *
     * @param   repository
     *          string repository
     * @param   folder
     *          user folder
     * @return  ture
     *          if folder is exist or false otherwise
     * @throws  SvnException
     *          if check operaion (command ls repository) finish with errors
     */
    public boolean isExistFolderInRepository(String repository, String folder) throws SvnException {
        logger.debug("isExistFolderInRepository() - invocation");

        ArrayList<String> folders = new ArrayList<>();
        boolean isExist = false;
        try {
            String[] commands = new String[]{"svn",
                    "--username", admin.get("passwd"), "--password", admin.get("passwd"),
                    "--no-auth-cache", "--non-interactive",
                    "ls", "svn://localhost/" + repository};

            Process process = Runtime.getRuntime().exec(commands);

            if(!isProcessErrors(process)){
                BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "utf-8"));
                String input;
                while ((input = inputReader.readLine()) != null) {
                    folders.add(input);
                }
                inputReader.close();
            }

            } catch (IOException e) {
            System.out.println("IOException isExistFolderInRepository - " + e.getMessage());
        }

        for (String s : folders) {
            if (s.equals(folder + "/"))
                isExist = true;
        }

        logger.debug("isExistFolderInRepository() - finish");
        return isExist;
    }

    /**
     * Creates the directory in File System
     *
     * @param   dirName the path string or initial part
     * @return  true,
     *          if the directory was created;
     * @throws  IOException
     *          if an I/O error occurs
     */
    private boolean createDirectory(String dirName) throws IOException {
        Files.createDirectories(Paths.get(dirName));
        return true;
    }

    /**
     * Deletes a directory.
     *
     * @param   dirName the path string or initial part
     * @throws  IOException
     *          if an I/O error occurs
     */
    private void removeDirectory(String dirName) throws IOException {
        Files.delete(Paths.get(dirName));
    }


    /**
     * Check Process for errors
     * @param process Process
     * @return false if no errors
     * @throws  IOException
     *          if an I/O error occurs
     * @throws  SvnException
     *          if Process has errors
     */
    private boolean isProcessErrors(Process process) throws IOException, SvnException {
        BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "utf-8"));
        ArrayList<String> errors = new ArrayList<>();
        String error;

        while ((error = errorReader.readLine()) != null) {
            errors.add(error);
        }
        errorReader.close();

        if (!errors.isEmpty()) {
            System.out.println(errors);
            throw new SvnException("Process Errors - "+errors);
        }
        return false;
    }
}
